package at.jku.ase.utils;

import at.jku.ase.communication.SessionObject;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

/**
 * Created by IntelliJ IDEA.
 * User: stellit
 * Date: 12/18/11
 * Time: 11:13 AM
 * To change this template use File | Settings | File Templates.
 */
public final class XMLUtils {

    private XMLUtils() {
    }

    private static final BASE64Encoder encoder = new BASE64Encoder();
    private static final BASE64Decoder decoder = new BASE64Decoder();

    public static final void startXMLStream(final XMLStreamWriter writer) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeStartDocument();
                writer.writeStartElement("stream");
            }
        }.execute();
    }

    public static final void endXMLStream(final XMLStreamWriter writer) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeEndDocument();
                writer.flush();
            }
        }.execute();
    }

    public static final void writePublicKey(final XMLStreamWriter writer, final SessionObject session) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                System.out.println("Write public key to output xml stream...");
                writer.writeStartElement("publicKey");
                writer.writeAttribute("id", session.getId());
                String publicKey = objToBase64(session.getMyPublicKey());
                writer.writeCData(publicKey);
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    private static final String objToBase64(final Object obj) {
        final Wrapper<byte[]> objBytes = new Wrapper<byte[]>();
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutput out = new ObjectOutputStream(bos);
                out.writeObject(obj);
                objBytes.set(bos.toByteArray());
                out.close();
                bos.close();
            }
        }.execute();

        return byteArrayToBase64(objBytes.get());
    }

    public static final String byteArrayToBase64(byte[] bytes) {
        return encoder.encode(bytes);
    }

    public static void writeEncryptedSecretKey(final XMLStreamWriter writer, final byte[] secret) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeStartElement("secretKey");
                writer.writeCData(byteArrayToBase64(secret));
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    public static void startTransmission(final XMLStreamWriter writer) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeStartElement("transmission");
                writer.flush();
            }
        }.execute();
    }

    public static void endTransmission(final XMLStreamWriter writer) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    public static void writeData(final XMLStreamWriter writer, final byte[] data) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeStartElement("data");
                writer.writeCData(byteArrayToBase64(data));
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    public static void writeSignature(final XMLStreamWriter writer, final byte[] signature) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                writer.writeStartElement("signature");
                writer.writeCData(byteArrayToBase64(signature));
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    public static void writeSignatureStatus(final XMLStreamWriter writer, final boolean signValid) {
        new OpThrowsException() {
            @Override
            public void op() throws Exception {
                String status = signValid ? "OK" : "FAIL";
                writer.writeStartElement("feedback");
                writer.writeCharacters(status);
                writer.writeEndElement();
                writer.flush();
            }
        }.execute();
    }

    public static byte[] base64ToByteArray(final String keyChars) {
        return new OpWithParameterThrowsException<byte[]>() {
            @Override
            public byte[] op() throws Exception {
                return decoder.decodeBuffer(keyChars);
            }
        }.execute();

    }
}
